#include "CommandParser.h"

#include <charconv>

#include "Log.h"

#include "CommandDispatcher.h"
#include "LoopManager.h"

//mpParentCommandDispatcher(pParentCommandDispatcher),mcommandExecutor(this)
CommandParser::CommandParser() {

    mcommandExecutor.mparentCommandParser = this;
}

CommandParser::~CommandParser() {
    //dtor

}



void CommandParser::parseCommand(NetworkString& data, NetworkString& result) {
    const NetworkString::value_type value = data[1];
    auto iterator = mcommandToFunction.find(value);

    if (iterator != mcommandToFunction.end()) {

        LOG_TO(BizLogHandle, UsedLogger::INFO, "execute command:%s", data.data());
//        data.remove_prefix(3);
//        data.remove_suffix(1);

        try {
            (this->*(iterator->second))(data, result);
            if (result.empty()) {
                result.append(data, 0, data.size() - 1);
            } else {
                result.insert(0, data, 0, 3);
                result.at(2) = '_';
            }
            result.append("_OK>\r\n");
        } catch (std::exception& ex) {
            result.assign(data, 0, data.size() - 1);
            result.append("_ERROR>\r\n");

            LOG_TO(BizLogHandle, UsedLogger::ERROR, "command execute error:%s", ex.what());
        }

    } else {
        LOG_TO(BizLogHandle, UsedLogger::ERROR, "not found command:%s", data.data());
    }

}



NetworkString& CommandParser::build(NetworkString& data, NetworkString& result, bool success, bool passive) {
    if (result.empty()) {
        result.append(data, 0, data.size() - 1);
    } else {
        if (data.empty()) {
            result.insert(0, 1, '<');
        } else {
            result.insert(0, data, 0, 3);
            result.at(2) = '_';
        }
    }

//    bool passive = true;

    if (passive) {
        if (success) {
            result.append("_OK>\r\n");
        } else {
            result.append("_ERROR>\r\n");
        }
    } else {
        result.append(">\r\n");
    }

    return result;
}



void CommandParser::buildAndSend(NetworkString& data, NetworkString& result, bool success, bool passive) {
    build(data, result, success, passive);

    mparentCommandDispatcher->send(result);
}



void CommandParser::requestOfflineCommand() {
    std::string* pRawString = new std::string{};
    std::string& requestCommand = *pRawString;
    std::string emptyCommand;
    onRequestOfflineCommand(emptyCommand, requestCommand);

    if (1 == mparentCommandDispatcher->mserverReady) { //服务器识别时，要晚一步发送离线指令请求
        ++mparentCommandDispatcher->mserverReady;
        mparentCommandDispatcher->getWorkPool()->pushPool(pRawString);

    } else {
        mparentCommandDispatcher->send(requestCommand);
        delete pRawString;
    }
}



void CommandParser::sendDoorStatus() {
    std::string rawString;
    std::string& requestCommand = rawString;
    std::string command = "<O>";
    bool success = true;
    try {
        onDoorStatus(command, requestCommand);
    } catch(std::exception& ex) {
        success = false;
        LOG_WARN(ex.what());
    }

    buildAndSend(command, requestCommand, success, false);
}


void CommandParser::sendCurrentAndVoltage() {
    std::string rawString;
    std::string& requestCommand = rawString;
    std::string command = "<U>";
    bool success = true;
    try {
        onCurrentAndVoltage(command, requestCommand);
    } catch(std::exception& ex) {
        success = false;
        LOG_WARN(ex.what());
    }

    buildAndSend(command, requestCommand, success, false);
}



void CommandParser::sendTemperatureAlarm(const std::string& threshold){
    std::string requestCommand;
    std::string command = "<T_";
    command += threshold;
    command += "_00_ALARM>";
    bool success = true;
    try {
        onTemperature(command, requestCommand);
    } catch(std::exception& ex) {
        success = false;
        LOG_WARN(ex.what());
    }

    buildAndSend(command, requestCommand, success, false);

}



void CommandParser::sendAcSwitchStatus(const std::string& switchMode, const std::string& loopSwitchStatus) {
    bool success = true;
    std::string requestCommand = "acSwitchStatus";
    try {
        mjsonCommandParser.buildAcSwitchStatusResponse(switchMode, loopSwitchStatus, requestCommand);
    } catch(std::exception& ex) {
        success = false;
        LOG_WARN(ex.what());
    }

    std::string command = "<Z>";

    buildAndSend(command, requestCommand, success, false);
}



void CommandParser::sendAlertInfo(const std::string& alertType, const std::string& data) {
    bool success = true;
    std::string requestCommand = "alert";
    try {
        mjsonCommandParser.buildAlertInfo(alertType, requestCommand);
    } catch(std::exception& ex) {
        success = false;
        LOG_WARN(ex.what());
    }

    std::string command = "<Z>";

    buildAndSend(command, requestCommand, success, false);
}



void CommandParser::onChannelOperated(NetworkString& detailCmd, std::string& result) {
    const LoopSize_t loopCount = LoopManagerSingleton::instance().updatePortCount();//detailCmd.length() - 4;
    std::time_t delaySeconds = 0;
    LoopCommandType commandType;
    NetworkString::size_type afterLoopIndex = detailCmd.find('_', 3);
    if (NetworkString::npos != afterLoopIndex){
        std::from_chars(&detailCmd[1 + afterLoopIndex], &detailCmd.back(), delaySeconds);
        commandType = LoopCommandType::ONLINE_DELAYED_COMMAND;
    } else {
        afterLoopIndex = detailCmd.length() - 1;
        commandType = LoopCommandType::ONLINE_COMMAND;
    }

    const LoopSize_t length = std::min(loopCount, afterLoopIndex - 3);
    LoopControlInfoPtr pLoopControlInfo{new(length) LoopControlInfo{length}, LoopControlInfo::releaseMemory};
    pLoopControlInfo->commandType = commandType;
    detailCmd.copy(reinterpret_cast<NetworkString::pointer> (pLoopControlInfo->loopStatus), length, 3);

    mcommandExecutor.onChannelOperated(pLoopControlInfo, delaySeconds, result);

    const char* pStart = &detailCmd[length + 3];
    if ('0' == *pStart || '1' == *pStart){
        VideoPlayInfo videoPlayInfo;
        std::string* pString = nullptr;
        int tempValue = 0;
        int writtenChars = 0;
        std::from_chars(pStart, pStart + 8, tempValue, 2);
        pString = &videoPlayInfo.videoId;
        pString->resize(3);
        writtenChars = snprintf(&(*pString)[0], pString->size() + 1, "%03d", tempValue);

        pStart += 8;
        pString = &videoPlayInfo.speed;
        std::from_chars(pStart, pStart + 4, tempValue, 2);
        *pString = '0' + tempValue;

        pStart += 4;
        pString = &videoPlayInfo.mode;
        std::from_chars(pStart, pStart + 4, tempValue, 2);
        *pString = '0' + tempValue;


        pStart += 4;
        pString = &videoPlayInfo.bright;
        std::from_chars(pStart, pStart + 8, tempValue, 2);
        pString->resize(3);
        writtenChars = snprintf(&(*pString)[0], pString->size() + 1, "%03d", tempValue);

        std::string result;
        mcommandExecutor.onVideoControl(videoPlayInfo, result);
    }

}


